package pentago.engine;

import java.awt.Point;

import pentago.exceptions.PentagoInvalidPlatePositionException;
import pentago.exceptions.PentagoInvalidPositionException;
import pentago.exceptions.PentagoInvalidRotationException;

public class Move {

    public static final byte UNKNOWN_ROTATION_DIRECTION = -1;
    public static final byte CLOCKWISE = 0;
    public static final byte COUNTERCLOCKWISE = 1;

    private Point marblePosition;
    private byte rotatedPlate;
    private byte plateRotation;

    public Move() {
	marblePosition = null;
	rotatedPlate = GameBoard.UNKNOWN_POSITION;
	plateRotation = UNKNOWN_ROTATION_DIRECTION;
    }

    public Move(Point marblePosition, byte rotatedPlate, byte plateRotation)
	    throws PentagoInvalidPositionException,
	    PentagoInvalidRotationException,
	    PentagoInvalidPlatePositionException {
	if (marblePosition.x < 0 || marblePosition.x > 5
		|| marblePosition.y < 0 || marblePosition.y > 5)
	    throw new PentagoInvalidPositionException();

	if (rotatedPlate != GameBoard.UPPER_LEFT
		&& rotatedPlate != GameBoard.UPPER_RIGHT
		&& rotatedPlate != GameBoard.LOWER_LEFT
		&& rotatedPlate != GameBoard.LOWER_RIGHT
		&& rotatedPlate != GameBoard.UNKNOWN_POSITION)
	    throw new PentagoInvalidPlatePositionException();

	if (plateRotation != CLOCKWISE && plateRotation != COUNTERCLOCKWISE
		&& plateRotation != UNKNOWN_ROTATION_DIRECTION)
	    throw new PentagoInvalidRotationException();

	this.rotatedPlate = rotatedPlate;
	this.marblePosition = marblePosition;
	this.plateRotation = plateRotation;
    }

    public void setRotation(byte rotation)
	    throws PentagoInvalidRotationException {
	if (rotation != CLOCKWISE && rotation != COUNTERCLOCKWISE
		&& rotation != UNKNOWN_ROTATION_DIRECTION)
	    throw new PentagoInvalidRotationException();
	this.plateRotation = rotation;
    }

    public byte getRotation() {
	return this.plateRotation;
    }

    public void setPosition(Point position)
	    throws PentagoInvalidPositionException {
	if (position.x < 0 || position.x > 5 || position.y < 0
		|| position.y > 5)
	    throw new PentagoInvalidPositionException();
	this.marblePosition = position;
    }

    public Point getPosition() {
	return this.marblePosition;
    }

    public byte getRotatedPlate() {
	return rotatedPlate;
    }

    public void setRotatedPlate(byte rotatedPlate)
	    throws PentagoInvalidPlatePositionException {
	if (rotatedPlate != GameBoard.UPPER_LEFT
		&& rotatedPlate != GameBoard.UPPER_RIGHT
		&& rotatedPlate != GameBoard.LOWER_LEFT
		&& rotatedPlate != GameBoard.LOWER_RIGHT
		&& rotatedPlate != GameBoard.UNKNOWN_POSITION)
	    throw new PentagoInvalidPlatePositionException();
	this.rotatedPlate = rotatedPlate;
    }

    public boolean executeMove() {
	if (!moveExecutable())
	    return false;
	plateRotation = UNKNOWN_ROTATION_DIRECTION;
	rotatedPlate = GameBoard.UNKNOWN_POSITION;
	marblePosition = null;
	return true;
    }

    private boolean moveExecutable() {
	return (plateRotation != UNKNOWN_ROTATION_DIRECTION
		&& rotatedPlate != GameBoard.UNKNOWN_POSITION && marblePosition != null);
    }

    public void rotateMarble(byte platePosition, byte direction) {

	int shiftRight = 0;
	int shiftDown = 0;

	// System.out.println("Przed: " + marblePosition.x + " "
	// + marblePosition.y);

	switch (platePosition) {
	case GameBoard.UPPER_RIGHT:
	    shiftRight = 3;
	    marblePosition.x -= shiftRight;
	    break;
	case GameBoard.LOWER_LEFT:
	    shiftDown = 3;
	    marblePosition.y -= shiftDown;
	    break;
	case GameBoard.LOWER_RIGHT:
	    shiftRight = 3;
	    shiftDown = 3;
	    marblePosition.x -= shiftRight;
	    marblePosition.y -= shiftDown;
	    break;
	}

	if (marblePosition.x == 1 && marblePosition.y == 1) {
	    marblePosition.x += shiftRight;
	    marblePosition.y += shiftDown;
	    return;
	}

	int x, y;
	if (direction == CLOCKWISE) {
	    x = 2 - marblePosition.y + shiftRight;
	    y = marblePosition.x + shiftDown;
	} else {
	    x = marblePosition.y + shiftRight;
	    y = 2 - marblePosition.x + shiftDown;
	}

	marblePosition.x = x;
	marblePosition.y = y;

	// System.out.println("Po: " + marblePosition.x + " " +
	// marblePosition.y);
    }
}
